﻿using System;
using System.IO;
using System.Threading.Tasks;
using hundsun.t2sdk;
using NLog;

namespace QuantBox.XApi
{
    public sealed class UfxClient
    {
        private readonly SubscribeCallback _subscribeCallback;
        private readonly FunctionCallback _functionCallback;
        private UfxConnection? _connection;
        private UfxAccountInfo? _accountInfo;
        private UserInfoField? _userInfo;
        private ServerInfoField? _serverInfo;
        private RspUserLoginField? _login;

        internal readonly QueryManager queryManager;
        internal readonly DealProcessor dealProcessor;
        internal readonly StatusPublisher statusPublisher;
        private volatile bool _connected;
        internal Logger logger = LogManager.CreateNullLogger();

        internal UfxErrorInfo AsyncCall(IUfxFunctionCall function)
        {
            return _connection!.AsyncCall(function);
        }

        public UfxClient(IXSpi spi)
        {
            Spi = spi;
            _subscribeCallback = new SubscribeCallback(this);
            _functionCallback = new FunctionCallback(this);
            queryManager = new QueryManager(this);
            dealProcessor = new DealProcessor(this);
            statusPublisher = new StatusPublisher(spi);
        }

        public IXSpi Spi { get; }

        public bool Connected => _connected;
        public UfxAccountInfo? AccountInfo => _accountInfo;

        public void Release()
        {
            Disconnect();
        }

        public void Connect(ServerInfoField server, UserInfoField user)
        {
            logger = LogManager.GetLogger($"Ufx.{user.UserID}");
            if (!File.Exists(server.ConfigPath)) {
                logger.Error($"没有找到配置文件,{server.ConfigPath}");
                return;
            }
            _userInfo = user;
            _serverInfo = server;
            _connection = new UfxConnection();
            _connection.ConnectionCreated += connection => connection.Create2BizMsg(_functionCallback);
            _connection.SubscriberCreated += connection => connection.Create2BizMsg(_functionCallback);
            _connection.Connected += OnUfxConnected;
            _connection.SubscriberConnected += OnSubscriberConnected;
            _connection.ErrorHappened += OnErrorHappened;
            _connection.LogHappened += OnLogHappened;
            statusPublisher.Post(ConnectionStatus.Connecting);
            _connection.Open(_serverInfo.ConfigPath);
        }

        private void OnLogHappened(string msg)
        {
            logger.Trace(msg);
        }

        private void OnErrorHappened(UfxErrorInfo error)
        {
            logger.Error($"连接错误,{error.ErrCode},{error.ErrMsg}");
        }

        private void OnSubscriberConnected(CT2Connection connection)
        {
            var error = _connection!.Subscribe(_userInfo!.UserID, _userInfo.Password, _subscribeCallback);
            if (error != UfxErrorInfo.Ok) {
                logger.Error($"订阅错误断开链接,{error.ErrCode},{error.ErrMsg}");
                Task.Run(Disconnect);
                return;
            }
            _connected = true;
            statusPublisher.Post(ConnectionStatus.Done, _login!);
        }

        private void OnUfxConnected(CT2Connection connection)
        {
            statusPublisher.Post(ConnectionStatus.Connected);
            statusPublisher.Post(ConnectionStatus.Logining);
            var error = _connection!.FuturesLogin(_userInfo!.UserID, _userInfo.Password, _serverInfo!.ExtInfoChar128);
            if (error != UfxErrorInfo.Ok) {
                logger.Error($"期货登录错误断开链接,{error.ErrCode},{error.ErrMsg}");
                Task.Run(Disconnect);
                return;
            }

            _login = new RspUserLoginField {
                AccountID = _userInfo.UserID,
                UserID = _userInfo.UserID,
                LoginTime = DateTime.Now.ToIntTime(),
                TradingDay = DateTime.Today.ToIntDate(),
                Text = "0"
            };
            statusPublisher.Post(ConnectionStatus.Logined, _login);

            (_accountInfo, error) = _connection.LoadAccountInfo();
            if (error != UfxErrorInfo.Ok) {
                logger.Error($"获取账户信息错误断开链接,{error.ErrCode},{error.ErrMsg}");
                Task.Run(Disconnect);
            }
        }

        public void Disconnect()
        {
            if (_connection == null) {
                return;
            }
            _connected = false;
            _connection.Close();
            _connection = null;
        }

        public void Query(QueryType type)
        {
            if (!_connected) {
                return;
            }
            queryManager.Post(type);
        }

        public string SendOrder(OrderField order)
        {
            return dealProcessor.SendOrder(order);
        }

        public void CancelOrder(string orderId)
        {
            if (_connected) {
                dealProcessor.CancelOrder(orderId);
            }
        }
    }
}